// Playground - noun: a place where people can play

import Cocoa

var str = "Hello, playground"

struct Page {
    let title: String
}
typealias JSON = AnyObject
typealias JSONArray = [JSON]

enum PageListResult {
    case Success([Page])
    case Failur(NSError)
}

enum JSONResult {
    case Success(JSON)
    case FailUre(NSError)
}

enum AResult<A>
{
    case Success(A)
    case Failure(NSError)
}
enum Result<A>
{
    case Success(Box<A>)
    case Failure(NSError)
}
final class Box<T> {
    let unbox: T
    init (_ value: T) {
        self.unbox = value
    }
}

//func asJSON(data: NSData) -> JSONResult
func asJSON(data: NSData) -> Result<JSON> {
    var error: NSError?
    let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(0), error: &error)
    switch (json,error)
    {
    case(_, .Some(let error)): return .Failure(error)
    case(.Some(let json), _): return .Success(Box(json))
        
    default:
      fatalError("Received neither JSON nor an error")
        return .Failure(NSError())
        
    }
    
}
extension NSError {
    convenience init(localizedDescription: String) {
        self.init(domain:"" ,code: 0 ,userInfo: [NSLocalizedDescriptionKey: localizedDescription])
    }
}

func pagesFromData(data: NSData) -> PageListResult {
    
    // 1. Parse the NSData into a JSON object
    var error: NSError?
    let json: JSON? = NSJSONSerialization.JSONObjectWithData(data,
        options: NSJSONReadingOptions(0), error: &error)
    
    if let json: JSON = json {
        
        // 2. Make sure the JSON object is an array
        if let array = json as? JSONArray {
            
            // 3. Get the second element
            if array.count < 2 {
                // Failure leg for 3
                return .Failure(NSError(localizedDescription: "Could not get second element. Got: \(array.count)"))
            }
            let element: JSON = array[1]
            
            // 4. Make sure the second element is a list of strings
            if let titles = element as? [String] {
                
                // 5. Convert those strings into pages
                return .Success(titles.map { Page(title: $0) })
            }
            else {
                // Failure leg for 4
                return .Failure(NSError(localizedDescription: "Expected string list. Got: \(array[1])"))
            }
        }
        else {
            // Failure leg for 2
            return .Failure(NSError(localizedDescription: "Expected array. Got: \(json)"))
        }
    }
    else if let error = error {
        // Failure leg for 1
        return .Failure(error)
    }
    else {
        fatalError("Received neither JSON nor an error")
        return .Failure(NSError())
    }
}

func pagesFromData(data: NSData) -> Result<[Page]> {
    return data
        >== asJSON
        >== asJSONArray
        >== atIndex(1)
        >== asStringList
        >== asPages
}
